import time

from ivic.vsched.Model import *
from ivic.vsched.Impl import Impl
from ivic.vsched.Interface import Interface

from ivic.core import Logging
logger = Logging.get_logger('ivic.vsched.Server')

def zeroReturnWrapper(fun):
    def __wrapper(*args, **kwargs):
        try:
            return fun(*args, **kwargs)
        except Exception, e:
            logger.exception(e)
            return 1
    return __wrapper

def nullReturnWrapper(fun):
    def __wrapper(*args, **kwargs):
        try:
            return fun(*args, **kwargs)
        except Exception, e:
            logger.exception(e)
            return None
    return __wrapper

class ServerClass(Interface):
    def __init__(self, config):
        # save config
        self.config = config

        # dump config string
        for k, v in self.config.items():
            if type(v) == str:
                logger.debug('config var: %s = %s', k, v)

        # init session and impl
        session = get_session(self.config['connect_string'])
	self.s = session
        self.impl = Impl(session)

    @zeroReturnWrapper
    def importTemplate(self, xml):
        '''import XML into Portal's database
    Return Value
        Integer 0 - for successfully import
        Integer ErrorIndex - for user to get import error'''
        self.impl.importTemplate(xml)
        return 0

    @nullReturnWrapper
    def listTemplate(self):
        '''list template
    Return Value:
        String - a list containing each template's UUID, Type, Name'''
        return self.impl.listTemplate()

    @nullReturnWrapper
    def listTemplate_ByType(self, typ):
        '''list template by `type`
    Argument `type` - vLab, vCluster, vTemplate
    Return Value:
        String - a list containing each template's UUID, Type, Name
        NULL - for invalid `type`'''
        return self.impl.listTemplate_ByType(typ)

    @nullReturnWrapper
    def listVmi_ByVlab(self, vlabInstance_uuid):
        return self.impl.listVmi_ByVlab(vlabInstance_uuid)

    @nullReturnWrapper
    def listVmi_ByVcluster(self, vclusterInstance_uuid):
	return self.impl.listVmi_ByVcluster(vclusterInstance_uuid)

    @nullReturnWrapper
    def listVSwitch_ByVlab(self, vlabInstance_uuid):
        return self.impl.listVSwitch_ByVlab(vlabInstance_uuid)

    @nullReturnWrapper
    def listVSwitch_ByVcluster(self, vclusterInstance_uuid):
        return self.impl.listVSwitch_ByVcluster(vclusterInstance_uuid)

    @nullReturnWrapper
    def listVlabInstance_ByTemp(self, uuid):
        '''list instance by temp uuid
    Argument uuid - a vlabtemp uuid
    Return Value:
        String - a list containing each template UUID, Name
        NULL - for invalid uuid'''
        return self.impl.listVlabInstance_ByTemp(uuid)

    @nullReturnWrapper
    def listVmTemp(self):
        return self.impl.listVmTemp()

    ## add by sishouyu
    @nullReturnWrapper
    def listAllVclusters(self):
        return self.impl.listAllVclusters()
    

    @nullReturnWrapper
    def vmi_create_time(self, uuid):
        return self.impl.getVmCreateTime(uuid)

    @nullReturnWrapper
    def vmi_recentstart_time(self, uuid):
        return self.impl.getVmRecentStartTime(uuid)

    @nullReturnWrapper
    def showTemplate(self, uuid):
        '''show template info by UUID
    Return Value:
        String - XML information of a template
        NULL - for invalid `key`'''
        return self.impl.showTemplate(uuid)

    @nullReturnWrapper
    def showInstance(self, uuid):
        '''show instance info by UUID
    Return Value:
        String - XML information of a instance
        NULL - fro invalid uuid'''
        return self.impl.showInstance(uuid)

    @nullReturnWrapper
    def showTemplate_ByKey(self, key):
        '''show template info by `key`
    Argument `key` - vLab@<int>, vCluster@<int>, vTemplate@<int>
    Return Value:
        String - XML information of a template
        NULL - for invalid `key`'''
        return self.impl.showTemplate_ByKey(key)

    @zeroReturnWrapper
    def removeTemplate(self, uuid):
        '''removeTemplate -- remove template according to specified uuid, also remove related instances'''
        self.impl.removeTemplate(uuid)
        return 0
    
    @zeroReturnWrapper
    def removeTemplate_ByKey(self, key):
        '''removeTemplate -- remove template according to specified key, also remove related instances'''
        self.impl.removeTemplate_ByKey(key)
        return 0

    @nullReturnWrapper
    def listInstance(self):
        '''list instance
    Return Value:
        String - a list containing each instance's UUID, Type, Name'''
        return self.impl.listInstance()

    @nullReturnWrapper
    def listInstance_ByType(self, typ):
        '''list instance by `type`
    Argument `type` - vLab, vCluster, vInstance
    Return Value:
        String - a list containing each instance's UUID, Type, Name
        NULL - for invalid `type`'''
        return self.impl.listInstance_ByType(xml, typ)

    @zeroReturnWrapper
    def set_worknode_count(self, uuid, new_count):
	self.impl.set_worknode_count(uuid, new_count)
	return 0

    @zeroReturnWrapper
    def set_vct_vmt(self, vct_uuid, vmt_uuid):
        self.impl.set_vct_vmt(vct_uuid, vmt_uuid)
        return 0

    @zeroReturnWrapper
    def get_vcluster_network_info(self, uuid):
        return self.impl.get_vcluster_network_info(uuid)

    @nullReturnWrapper
    def get_vcluster_dnat_info(self, uuid):
	    return self.impl.get_vcluster_dnat_info(uuid)
    
    @nullReturnWrapper
    def to_do_vcluster_scale(self, uuid, op, num):
        return self.impl.to_do_vcluster_scale(uuid, op, num)

    @nullReturnWrapper
    def get_vcluster_status(self, uuid):
        return self.impl.get_vcluster_status(uuid)

    @nullReturnWrapper
    def get_vcluster_mu_vnc(self,uuid):
	    return self.impl.get_vcluster_mu_vnc(uuid)
	
    @nullReturnWrapper
    def get_vcluster_mu_uuid(self, uuid):
	    return self.impl.get_vcluster_mu_uuid(uuid)

    def removeInstance(self, uuid):
        '''removeInstance -- remove instance according to specified uuid, also remove related instances'''
        self.impl.removeInstance(uuid)
        return 0
    
    def removeInstance_ByKey(self, key):
        '''removeInstance -- remove instance according to specified key, also remove related instances'''
        self.impl.removeInstance_ByKey(key)
        return 0

    def __wait_job(self, id):
        while True:
            job = self.s.query(Job).get(id)
            if job.status == 'finished':
                return 0
            elif job.status == 'failed':
                return 1
            self.s.close()
            time.sleep(1)

    @zeroReturnWrapper
    def deployV(self, template_uuid, param):
        '''deploy template by UUID, with parameters defined in param
    Return Value:
        Integer 0 - for successfully deploy
        Integer ErrorIndex - for user to get deploy error'''
        jobid, uuid = self.impl.deployV(template_uuid, param)
        '''
        re = self.__wait_job(jobid)
        '''
        return uuid
    
    @zeroReturnWrapper
    def redeployV(self, uuid):
        '''redeploy VLab/VCluster by UUID, assume instance already exist but in state invalid
    Return Value:
        Integer 0 - for successfully redeploy
        Integer ErrorIndex - for user to get template export error'''
        jobid = self.impl.redeployV(uuid)
        return self.__wait_job(jobid)
    
    @zeroReturnWrapper
    def startV(self, uuid):
        '''start VLab/VCluster by UUID
    Return Value:
        Integer 0 - for successfully start
        Integer ErrorIndex - for user to get template export error'''
        jobid = self.impl.startV(uuid)
        return self.__wait_job(jobid)
    
    @zeroReturnWrapper
    def stopV(self, uuid):
        '''stop VLab/VCluster by UUID
    Return Value:
        Integer 0 - for successfully stop
        Integer ErrorIndex - for user to get template export error'''
        jobid = self.impl.stopV(uuid)
        return self.__wait_job(jobid)

    @zeroReturnWrapper
    def undeployV(self, uuid):
        '''undeploy VLab/VCluster by UUID
    Return Value:
        Integer 0 - for successfully start
        Integer ErrorIndex - for user to get template export error'''
        jobid = self.impl.undeployV(uuid)
        return self.__wait_job(jobid)
    
    @zeroReturnWrapper
    def deployV_ByKey(self, template_key):
        '''deploy template by Key
    Return Value:
        Integer 0 - for successfully deploy
        Integer ErrorIndex - for user to get deploy error'''
        jobid = self.impl.deployV_ByKey(key)
        return self.__wait_job(jobid)
    
    @zeroReturnWrapper
    def redeployV_ByKey(self, key):
        '''redeploy VLab/VCluster by Key, assume instance already exist but in state invalid
    Return Value:
        Integer 0 - for successfully redeploy
        Integer ErrorIndex - for user to get template export error'''
        jobid = self.impl.redeployV_ByKey(key)
        return self.__wait_job(jobid)
    
    @zeroReturnWrapper
    def startV_ByKey(self, key):
        '''start VLab/VCluster by Key
    Return Value:
        Integer 0 - for successfully start
        Integer ErrorIndex - for user to get template export error'''
        jobid = self.impl.startV_ByKey(key)
        return self.__wait_job(jobid)
    
    @zeroReturnWrapper
    def stopV_ByKey(self, key):
        '''stop VLab/VCluster by Key
    Return Value:
        Integer 0 - for successfully stop
        Integer ErrorIndex - for user to get template export error'''
        jobid = self.impl.stopV_ByKey(key)
        return self.__wait_job(jobid)

    @zeroReturnWrapper
    def undeployV_ByKey(self, key):
        '''undeploy VLab/VCluster by Key
    Return Value:
        Integer 0 - for successfully start
        Integer ErrorIndex - for user to get template export error'''
        jobid = self.impl.undeployV_ByKey(key)
        return self.__wait_job(jobid)
    
    def getError(self, index):
        '''get error message from previous operations
    Return Value:
        String - for error Message
        NULL - for bad index value'''
        return 'No Information'
